package json.jackson;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator;
import json.User;
import org.junit.Test;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.List;

/**
 * @describe: Jackson是用来序列化和反序列化json的Java的开源框架。Spring MVC的默认json解析器便是Jackson。
    与Gson等相比， Jackson解析大的json文件速度比较快; 运行时占用内存比较低，性能比较好。
 * @author: houkai
 */
public class JacksonDemo {

    /**
     * 序列化以及反序列化
     *  Jackson 最常用的API就是基于"对象绑定"的ObjectMapper。
     *  注意：反序列化对象必须存在默认的无参构造函数，否则会存在异常
     */
    @Test
    public void aTest() throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
        User user = User.init();
        String jsonString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(user);
        user = mapper.readValue(jsonString, User.class);
        System.out.println(user.toString());
    }

    /**
     * 序列化以及反序列化的配置
     */
    @Test
    public void bTest() throws JsonProcessingException {
        User user = User.init_1();
        ObjectMapper mapper = new ObjectMapper();
        //在反序列化时忽略在json中存在但Java对象不存在的属性
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        //在序列化时日期格式默认为 yyyy-MM-dd'T'HH:mm:ss.SSSZ
        mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false);
        //在序列化时忽略值为null的属性
        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        //忽略值为默认值的属性
        mapper.setDefaultPropertyInclusion(JsonInclude.Include.NON_DEFAULT);
        String userJson = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(user);
        System.out.println(userJson);
    }

    /**
     * 从文件/URL/InputStream中读取json 并反序列化
     */
    @Test
    public void cTest() throws IOException {
        ObjectMapper objectMapper = new ObjectMapper();
        File file = new File("user.json");
        User user = objectMapper.readValue(file, User.class);

        URL url = new URL("file:user.json");
        user = objectMapper.readValue(url, User.class);

        InputStream input = new FileInputStream("user.json");
        user = objectMapper.readValue(input, User.class);
    }

    /**
     * 对泛型的支持
     */
    @Test
    public void dTest() throws JsonProcessingException {
        String jsonArray ="[\"1\",\"2\"]";
        ObjectMapper objectMapper = new ObjectMapper();
        List<String> list = objectMapper.readValue(jsonArray, new TypeReference<List <String >>(){});
        System.out.println(list);
    }

    /**
     * 树模型
     */
    @Test
    public void eTest() throws JsonProcessingException {
        String carJson = "{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";
        ObjectMapper objectMapper = new ObjectMapper();
        JsonNode jsonNode = objectMapper.readValue(carJson, JsonNode.class);
        System.out.println(jsonNode.toString());

        //通过valueToTree 可以将对象转换为树结构
        JsonNode jsonNode1 = objectMapper.valueToTree("树形结构对象");
    }

    /**
     * 普通的yarm对象 序列化和反序列化
     */
    @Test
    public void fTest() throws JsonProcessingException {
        //普通
        ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory());
        Employee employee = new Employee("John Doe", "john@doe.com");
        String yamlString = objectMapper.writeValueAsString(employee);
        System.out.println(yamlString);

        Employee employee2 = objectMapper.readValue(yamlString, Employee.class);
        System.out.println(employee2);
    }

    /**
     * 读取yml文件
     */
    @Test
    public void gTest() throws IOException {
        ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
        InputStream  inputStream = this.getClass().getClassLoader().getResourceAsStream("EmployeeYaml.yml");

        Employee employee = mapper.readValue(inputStream, Employee.class);
        System.out.println(employee.toString());
    }

    /**
     * 写入yml文件
     * @throws IOException
     */
    @Test
    public void hTest() throws IOException {
        //去掉三个破折号
        ObjectMapper  mapper = new ObjectMapper(new YAMLFactory().disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER));
        //禁用掉把时间写为时间戳
        mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

        Employee employee = new Employee("test2", "999@qq.com");
        mapper.writeValue(new File("EmployeeYamlOutput.yml"), employee);
    }
}
